<?php
//-------------------------------------------------------------------------
// OVIDENTIA http://www.ovidentia.org
// Ovidentia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//-------------------------------------------------------------------------
/**
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
 * @copyright Copyright (c) 2010 by CANTICO ({@link http://www.cantico.fr})
 */
include_once 'base.php';
include_once dirname(__FILE__).'/inputwidget.class.php';



/**
 * Constructs a Widget_Select.
 *
 * @param string		$id			The item unique id.
 * @return Widget_Select
 */
function Widget_Select($id = null)
{
	return new Widget_Select($id);
}


/**
 * A Widget_Select is a widget that let the user select an option from a list of
 * available choices.
 * It is usually displayed as a drop down list unless the setSize method is used
 * with a non null parameter.
 */
class Widget_Select extends Widget_InputWidget implements Widget_Displayable_Interface 
{
	/**
	 * The reserved optgroup name used to specified options without an optgroup.
	 */
	const NOGROUPKEY = 'No optgroup defined';

	private $_options = array();

	private $_size = null;
	
	/**
	 * All options are objects Widget_SelectOption
	 * @var bool
	 */
	private $optionsAsObject = true;

	/**
	 * @param string $id			The item unique id.
	 * @return Widget_Select
	 */
	public function __construct($id = null)
	{
		parent::__construct($id);
	}


	/**
	 * Add class on selected option (selected by the value of an option)
	 * @param	string			$key 		value of selected option
	 * @param	string			$class		Class to add to the option
	 * @param	string 			$optgroup
	 * @return	Widget_Select	$this
	 */
	public function addOptionClass($key, $class ,$optgroup = self::NOGROUPKEY)
	{
		if (!isset($this->_options[$optgroup][$key]))
		{
			throw new Exception(sprintf('the option %s does not exists', $key));
		}
		
		if (!($this->_options[$optgroup][$key] instanceof Widget_SelectOption))
		{
			$this->_options[$optgroup][$key] = new Widget_SelectOption($key, $this->_options[$optgroup][$key]);
		}
		$this->_options[$optgroup][$key]->addClass($class);
		
		return $this;
	}





	/**
	 * (non-PHPdoc)
	 * @see programs/widgets/Widget_InputWidget::getClasses()
	 */
	public function getClasses()
	{
		$classes = parent::getClasses();
		$classes[] = 'widget-select';
		return $classes;
	}


	/**
	 * Sets the number of lines which will be displayed.
	 * 
	 * @param int $value		The number of lines to display, or null to
	 * 							have a drop-down list (default behavior).
	 * @return Widget_Select
	 */
	public function setSize($value)
	{
		$this->_size = $value;
		return $this;
	}


	/**
	 * Gets the number of lines which will be displayed.
	 * 
	 * @return int		The number of lines which will be displayed or null if
	 * 					the select is displayed as a drop-down list (default behavior).
	 */
	public function getSize()
	{
		return $this->_size;
	}


	/**
	 * Set options with optional optgroup.
	 * 
	 * @param	array 	$options	An array of options [ value => text ]
	 * @param	string	$optgroup	If specified, the options will appear in a group labelled $optgroup 
	 * 
	 * @return 	Widget_Select
	 */
	public function setOptions($options, $optgroup = self::NOGROUPKEY)
	{
		$this->optionsAsObject = false;
		$this->_options[$optgroup] = $options;
		return $this;
	}
	
	/**
	 * Adds an option to the select.
	 * 
	 * @param 	string | Widget_SelectOption 	$option 	Value of select option or SelectOption Widget
	 * @param	string | null					$text 		Text display for the select option
	 * @param	string							$optgroup	If specified, the option will appear in a group labelled $optgroup
	 * 
	 * @return 	Widget_Select
	 */
	public function addOption($option, $text = null, $optgroup = self::NOGROUPKEY)
	{
		if ($option instanceof Widget_SelectOption)
		{
			$this->_options[$optgroup][$option->getValue()] = $option;
			$option->setParent($this);
		} else {
			assert('(null !== $text); /* The "text" parameter must be a string */');
			$this->_options[$optgroup][$option] = $text;
			$this->optionsAsObject = false;
		}
		
		
		return $this;
	}
	
	/**
	 * Set all options as objects
	 * @return Widget_Select
	 */
	private function optionsAsObjects()
	{
		if ($this->optionsAsObject)
		{
			return $this;
		}
		
		foreach($this->_options as &$arrOptions)
		{
			foreach($arrOptions as $value => $text)
			{
				if (!($text instanceof Widget_SelectOption))
				{
					$arrOptions[$value] = new Widget_SelectOption($value, $text);
				}
			}
		}
		
		$this->optionsAsObject = true;
		return $this;
	}
	
	/**
	 * @param	string	$value
	 * @param	string	$text
	 */
	public function SelectOption($value, $text)
	{
		return new Widget_SelectOption($value, $text);
	}
	
	
	
	/**
	 * Sorts the options and option groups alphabetically in the select.
	 *
	 * @return 	Widget_Select
	 */
	public function sortOptions()
	{
		$this->optionsAsObjects();
		
		ksort($this->_options);
		
		foreach($this->_options as $optgroup => $arrOptions) {
			bab_Sort::sortObjects($this->_options[$optgroup]);
		}

		return $this;
	}
	
	
	/**
	 * get options with optgroups
	 * @return array
	 */
	public function getOptGroups()
	{
		$tree = $this->_options;
		
		if (isset($tree[self::NOGROUPKEY])) {
			unset($tree[self::NOGROUPKEY]);
		}
		
		return $tree;
	}
	
	
	
	/**
	 * Get options without optgroups
	 * @return 	array
	 */
	public function getOptions()
	{	
		if (!isset($this->_options[self::NOGROUPKEY])) {
			return array();
		}
		
		return $this->_options[self::NOGROUPKEY];
	}
	
	
	/**
	 * Set another select with optgroup as values 
	 * A javascript will use the two combined select for contextual navigation
	 * @return Widget_Select
	 */
	public function setAssociatedOptgroupSelect(Widget_Select $optgroupselect)
	{
		$this->setMetadata('optgroupselect', $optgroupselect->getId());
		return $this;
	}
	
	
	
	


	/**
	 * (non-PHPdoc)
	 * @see programs/widgets/Widget_Displayable_Interface::display()
	 */
	public function display(Widget_Canvas $canvas)
	{
		foreach($this->_options as &$optgroup) {
			if (isset($optgroup[$this->getValue()]))
			{
				$selected = $optgroup[$this->getValue()];
				if (!($selected instanceof Widget_SelectOption))
				{
					$selected = new Widget_SelectOption($this->getValue(), $selected);
					$optgroup[$this->getValue()] = $selected;
				}
				
				$selected->selected();
				break;
			}
		}
		
		
		if ($this->isDisplayMode()) {

			$classes = $this->getClasses();
			$classes[] = 'widget-displaymode';

			$value = '';
			$key = $this->getValue();

			if (isset($this->_options[self::NOGROUPKEY][$key])) {
				$value = $this->_options[self::NOGROUPKEY][$key]->__toString();
			} else {

				foreach($this->_options as $group => $arr) {
					if (isset($arr[$key])) {
						$value = $group.' > '.$arr[$key]->__toString();
						break;
					}
				}
			}

			return $canvas->richtext(
					$this->getId(), 
					$classes, 
					$value, 
					BAB_HTML_ALL ^ BAB_HTML_P,
					$this->getCanvasOptions()
			);

		}


		return $canvas->select(
			$this->getId(),
			$this->getClasses(),
			$this->getFullName(),
			$this->getValue(),
			$this->getOptions(),
			$this->getOptGroups(),
			$this->isDisabled(),
			$this->getSize(),
			$this->getCanvasOptions()
		) . $canvas->metadata($this->getId(), $this->getMetadata());
	}

}





class Widget_SelectOption extends Widget_Widget
{
	private $value;
	
	private $text;
	
	/**
	 * 
	 * @var bool
	 */
	private $selected;
	
	/**
	 * @param string $id			The item unique id.
	 * @return Widget_Select
	 */
	public function __construct($value, $text, $id = null)
	{
		parent::__construct($id);
		
		$this->value = $value;
		
		$this->text = $text;
	}
	
	
	public function getValue()
	{
		return $this->value;
	}
	
	
	/**
	 * Set the option selected or not
	 * @param	bool	$selected
	 */
	public function selected($selected = true)
	{
		$this->selected = $selected;
		return $this;
	}
	
	/**
	 * Used in option ordering
	 * @return string
	 */
	public function __tostring()
	{
		return $this->text;
	}
	
	
	/**
	 * @return string
	 */
	public function display(Widget_Canvas $canvas)
	{
		return $canvas->selectOption(
			$this->value,
			$this->text,
			$this->getClasses(),
			$this->selected,
			$this->getTitle(),
			$this->isDisabled(),
			$this->getCanvasOptions()
		);
	}
}
